#include "IntToPerdoTranslator.h"
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

void IntToPerdoTranslator::writeBeginning()
{
	vector<int> ids = sym->getArrayIds();
	int peak = sym->getPeak();

	for( vector<int>::iterator it = ids.begin(); it != ids.end(); it++ )
	{
		*out << "store " << peak << " " << *it << endl;
		peak++;
	}

	*out << "store " << peak << " 0" << endl;
}

void IntToPerdoTranslator::translate()
{
	string sLine;

	while( std::getline(*in, sLine, '\n') )
	{
		if( sLine.find(":") != string::npos && sLine.find("':'") == string::npos )
		{
			*out << sLine << endl;
			*out << sLabel;
			sLabel = "";
		}
		else
		{
			stringstream ss(sLine);
			if( !ss.eof() )
			{
				string sWord;
				ss >> sWord;
				OutputCase(sWord, ss);
			}
		}
	}
}

/*
///////////////////////////////////////////
		*out << sWord << " ";
		while( !ss.eof() )
		{
			string sWord;
			ss >> sWord;
			*out << sWord << " ";
		}
		*out << endl;
///////////////////////////////////////////
*/

void IntToPerdoTranslator::OutputCase(string sWord, stringstream & ss)
{
	if( sWord == "add" || sWord == "sub" || sWord == "mult" || sWord == "div" || sWord == "mod" )
	{
		string sArg;
		string A1;
		string A2;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else
			A1 = sArg;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regB" << endl;
			A2 = "regB";
		}
		else
			A2 = sArg;

		*out << sWord << " " << A1 << " " << A2 << " regA" << endl;
		ss >> sArg;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "val_copy" )
	{
		string sArg;

		ss >> sArg;
		if( sArg[0] == 's' )
			*out << "mem_copy " << sArg.substr(1, sArg.size() - 1) << " ";
		else if( sArg == "\'" )
		{
			sArg = "\' \'";
			*out << "store " << sArg << " ";
			ss >> sArg;      // This gets rid of the other ' (tick)
		}
		else
			*out << "store " << sArg << " ";

		ss >> sArg;
		*out << sArg.substr(1, sArg.size() -1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "if_less" || sWord == "if_gtr" || sWord == "if_less_equ" || sWord == "if_gtr_equ" || sWord == "if_equ" || sWord == "if_n_equ" )
	{
		string sArg;
		string A1;
		string A2;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else if( sArg == "\'" )
		{
			A1 = "\' \'";
			ss >> sArg;      // This gets rid of the other ' (tick)
		}
		else
			A1 = sArg;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regB" << endl;
			A2 = "regB";
		}
		else if( sArg == "\'" )
		{
			A2 = "\' \'";
			ss >> sArg;      // This gets rid of the other ' (tick)
		}
		else
			A2 = sArg;

		*out << sWord << " " << A1 << " " << A2;

		bool store = false;

		if( !ss.eof() )
		{
			ss >> sArg;
			*out << " regC" << endl;
			store = true;
		}
		else
		{
			*out << endl;
		}

		*out << "nop" << endl;

		if( store )
			*out << "store regC " << sArg.substr(1, sArg.size() - 1) << endl;

		*out << "if_equ regC 0" << endl;
		string label = getLabel();
		*out << "jump " << label << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = label + ":\n";
	}
	else if( sWord == "jump" )
	{
		string sArg;
		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			*out << "jump regA" << endl;
		}
		else
		{
			*out << sWord << " " << sArg << endl;
		}

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "nop" )
	{
		*out << sWord << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if ( sWord == "time" )
	{
		string sArg;
		*out << "time regA" << endl;
		// Grab the argument after time
		ss >> sArg;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "random" )
	{
		//random src1 dest - Intermediate
		//random src1 dest - Perdo
		string sArg;
		string A1;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else
			A1 = sArg;

		*out << "random " << A1 << " regB" << endl;

		ss >> sArg;
		*out << "store regB " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "out_num" || sWord == "out_char" || sWord == "err_num" || sWord == "err_char" )
	{
		string sArg;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			*out << sWord << " regA" << endl;
		}
		else if( sArg == "\'" )
		{
			*out << sWord << " \' \'" << endl;
			ss >> sArg;     // This gets rid of the other ' (tick)
		}
		else
		{
			*out << sWord << " " << sArg << endl;
		}

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "rotate" )
	{
		//void set_rotate(number angle);
		//rotate src
		string sArg;
		string A1;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else
			A1 = sArg;

		*out << "rotate " << A1 << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "rotate_stat" )
	{
		//number get_rotate();
		//rotate_stat dest
		string sArg;
		ss >> sArg; 
		*out << "rotate_stat regA" << endl;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "move" )
	{
		//void set_move(number distance);
		//move src
		string sArg;
		string A1;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else
			A1 = sArg;

		*out << "move " << A1 << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "move_stat" )
	{
		//number get_move();
		//move_stat dest
		string sArg;
		ss >> sArg; 
		*out << "move_stat regA" << endl;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "shields" )
	{
		//void set_shields(number energy);
		//shields src
		string sArg;
		string A1;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else
			A1 = sArg;

		*out << "shields " << A1 << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "shield_stat" )
	{
		//number get_shields();
		//shield_stat dest
		string sArg;
		ss >> sArg; 
		*out << "shield_stat regA" << endl;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "fire" )
	{
		//void fire(number energy);
		//fire src
		string sArg;
		string A1;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
			A1 = "regA";
		}
		else
			A1 = sArg;

		*out << "fire " << A1 << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "energy_stat" )
	{
		//number get_energy();
		//energy_stat dest
		string sArg;
		ss >> sArg; 
		*out << "energy_stat regA" << endl;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "scan" )
	{
		//number scan_distance();
		//scan distance ID angle
		string sArg;
		//We want the first argument, we don't care about the others
		ss >> sArg; 
		*out << "scan regA regB regC" << endl;
		*out << "store regA " << sArg.substr(1, sArg.size() - 1) << endl;
		ss >> sArg; 
		*out << "store regB " << sArg.substr(1, sArg.size() - 1) << endl;
		ss >> sArg; 
		*out << "store regC " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "array_get_index" )
	{
		string sArg;
		string A1;

		ss >> sArg;
		*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regB" << endl;
			A1 = "regB";
		}
		else
			A1 = sArg;

		*out << "add " << A1 << " regA regA" << endl;
		*out << "add 1 regA regA" << endl;
		ss >> sArg;
		*out << "mem_copy regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "array_set_index" )
	{
		string sArg;
		string A1;

		ss >> sArg;
		*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;

		ss >> sArg;
		if( sArg[0] == 's' )
		{
			*out << "load " << sArg.substr(1, sArg.size() - 1) << " regB" << endl;
			A1 = "regB";
		}
		else
			A1 = sArg;

		*out << "add " << A1 << " regA regA" << endl;
		*out << "add 1 regA regA" << endl;

		ss >> sArg;
		if( sArg[0] == 's' )
			*out << "mem_copy " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
		else if( sArg == "\'" )
		{
			sArg = "\' \'";
			*out << "store " << sArg << " regA" << endl;
			ss >> sArg;      // This gets rid of the other ' (tick)
		}
		else
			*out << "store " << sArg << " regA" << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "array_get_size" )
	{
		string sArg;

		ss >> sArg;
		*out << "load " << sArg.substr(1, sArg.size() - 1) << " regA" << endl;
		ss >> sArg;
		*out << "mem_copy regA " << sArg.substr(1, sArg.size() - 1) << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "array_set_size" )
	{
		string sArg;
		string A1;

		ss >> sArg;
		sArg = sArg.substr(1, sArg.size() - 1);
		ss >> A1;
		if( A1[0] == 's' )
		{
			*out << "load " << A1.substr(1, A1.size() - 1) << " regB" << endl;
			A1 = "regB";
		}

		//////////////////////////////////////////////////////////////////////

		string XXX = getLabel();
		string DONEWHILE = getLabel();
		string WHILE = getLabel();

		*out << "load " << sArg << " regA" << endl;
		*out << "load regA regF" << endl;
		*out << "if_gtr " << A1 << " regF" << endl;
		*out << "jump " << XXX << endl;
		*out << "store " << A1 << " regA" << endl;
		*out << "jump " << DONEWHILE << endl;
		*out << XXX << ":" << endl;
		*out << "load 0 regC" << endl;
		*out << "store regC " << sArg << endl;
		*out << "store " << A1 << " regC" << endl;
		*out << "add " << A1 << " regC regE" << endl;
		*out << "add 1 regE regE" << endl;
		*out << "store regE 0" << endl;
		*out << "add 1 regA regA" << endl;
		*out << "add 1 regC regC" << endl;
		*out << "add regF regA regD" << endl;
		*out << WHILE << ":" << endl;
		*out << "if_equ regA regD" << endl;
		*out << "jump " << DONEWHILE << endl;
		*out << "mem_copy regA regC" << endl;
		*out << "add 1 regA regA" << endl;
		*out << "add 1 regC regC" << endl;
		*out << "jump " << WHILE << endl;
		*out << DONEWHILE << ":" << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else if( sWord == "array_copy" )
	{
		string A1;
		string A2;
		
		ss >> A1;
		ss >> A2;

		A1 = A1.substr(1, A1.size() - 1);
		A2 = A2.substr(1, A2.size() - 1);
		
		string copy_shit = getLabel();
		string done = getLabel();
		string start = getLabel();

		*out << "load " << A1 << " regA" << endl;
		*out << "load regA regB" << endl;
		*out << "load " << A2 << " regC" << endl;
		*out << "load regC regD" << endl;
		*out << "add regA regB regE" << endl;
		*out << "add 1 regE regE" << endl;
		*out << "if_gtr_equ regD regB" << endl;
		*out << "jump " << copy_shit << endl;
		*out << "load 0 regC" << endl;
		*out << "store regC " << A2 << endl;
		*out << "store regB regC" << endl;
		*out << copy_shit << ":" << endl;
		*out << "add 1 regC regC" << endl;
		*out << "add 1 regA regA" << endl;
		*out << start << ":" << endl;
		*out << "if_equ regA regE" << endl;
		*out << "jump " << done << endl;
		*out << "mem_copy regA regC" << endl;
		*out << "add 1 regC regC" << endl;
		*out << "add 1 regA regA" << endl;
		*out << "jump " << start << endl;
		*out << done << ":" << endl;
		*out << "store regC 0" << endl;

		// Ouput the label, then set the label (Every command must do this at the end -- b/c of flow commands)
		*out << sLabel;
		sLabel = "";
	}
	else
	{
		cerr << "Unrecognized command: " << sWord << endl;
		exit(1);
	}
}

string IntToPerdoTranslator::getLabel()
{
	labelCount++;
	stringstream ss;
	ss << labelCount;
	return string("P") + ss.str();
}

